package com.flow.framework.module.call.rpc.decoder;

import com.fasterxml.jackson.core.type.TypeReference;
import com.flow.framework.common.error.SystemErrorCode;
import com.flow.framework.common.exception.CheckedException;
import com.flow.framework.common.json.ObjectMapperHolder;
import com.flow.framework.common.util.collection.CollectionUtil;
import com.flow.framework.common.util.verify.VerifyUtil;
import com.flow.framework.core.constant.FrameworkCoreConstant;
import com.flow.framework.core.response.Response;
import com.flow.framework.core.system.listener.lifecycle.ISystemLifecycleListener;
import com.flow.framework.core.util.HttpContentTypeUtil;
import com.flow.framework.core.util.ProxyUtil;
import com.flow.framework.module.call.rpc.manager.FeignManager;
import feign.Target;
import lombok.extern.slf4j.Slf4j;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * RPC调用辅助类
 *
 * @author luoguopiao
 * @version 0.0.1
 * @date 2022/2/19
 */
@Slf4j
public class RpcHelper implements ISystemLifecycleListener {

    /**
     * Feign.Builder的
     */
    private static FeignManager feignManager;

    /**
     * 判断RPC请求是否为内部请求
     *
     * @param response rpc原始响应
     * @return 是否为内部请求
     */
    static boolean isInnerRequest(feign.Response response) {
        Target<?> target = response.request().requestTemplate().feignTarget();
        return feignManager.isInnerRequest(target);
    }

    /**
     * rpc原始响应是否为文本型body
     *
     * @param headers rpc原始响应header
     * @return 是否为文本型body
     */
    static boolean isTextBody(Map<String, Collection<String>> headers) {
        Collection<String> contentTypes = headers.get("content-type");
        if (contentTypes == null || contentTypes.size() == 0) {
            return false;
        }

        for (String contentType : contentTypes) {
            boolean isTextBody = HttpContentTypeUtil.isTextBody(contentType);
            if (isTextBody) {
                return true;
            }
        }
        return false;
    }

    /**
     * 响应是否失败
     *
     * @return 是否失败
     */
    static boolean isResponseFailed(Response<?> response) {
        if (null == response) {
            log.error("framework response is null.");
            return true;
        }
        return !response.isSuccess();
    }

    static Response<String> getFrameworkResponse(Map<String, Collection<String>> headers, String url) {
        Collection<String> frameworkResponseHeaders = headers.get(FrameworkCoreConstant.FRAMEWORK_RESPONSE_KEY);
        if (!VerifyUtil.isEmpty(frameworkResponseHeaders)) {
            String frameworkResponseHeader = CollectionUtil.getFirstElement(frameworkResponseHeaders);
            if (!VerifyUtil.isEmpty(frameworkResponseHeader)) {
                try {
                    String decode = URLDecoder.decode(frameworkResponseHeader, StandardCharsets.UTF_8.name());
                    return ObjectMapperHolder.getInstance().readValue(decode, new TypeReference<Response<String>>() {
                    });
                } catch (Exception e) {
                    log.error("remote procedure call error, required response body is error, url:{}, framework response : {}",
                            url, frameworkResponseHeader);
                    throw new CheckedException(SystemErrorCode.REMOTE_PROCEDURE_CALL_ERROR);
                }
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    static void throwExceptionByFrameworkResponse(Response frameworkResponse) {
        if (null != frameworkResponse) {
            String system = frameworkResponse.getSystem();
            String code = frameworkResponse.getCode();
            String msg = frameworkResponse.getMsg();
            List<String> params = frameworkResponse.getParams();

            String srcSystem = frameworkResponse.getSrcSystem();
            String srcCode = frameworkResponse.getSrcCode();
            String srcMsg = frameworkResponse.getSrcMsg();
            List<String> srcParams = frameworkResponse.getSrcParams();
            log.error("throw exception from framework response. system : {}, code {}, msg : {}, params : {}, " +
                            "srcSystem : {}, srcCode : {}, srcMsg : {}, srcParams : {}",
                    system, code, msg, params, srcSystem, srcCode, srcMsg, srcParams);
            if (!VerifyUtil.isEmpty(srcCode)) {
                throw new CheckedException(SystemErrorCode.REMOTE_PROCEDURE_CALL_ERROR, srcSystem, srcCode, srcMsg, srcParams);
            }
            throw new CheckedException(SystemErrorCode.REMOTE_PROCEDURE_CALL_ERROR, system, code, msg, params);
        } else {
            log.error("framework response is null.");
            throw new CheckedException(SystemErrorCode.REMOTE_PROCEDURE_CALL_ERROR);
        }
    }

    @Override
    public void onStartUp() {
        feignManager = ProxyUtil.getProxied(FeignManager.class);
    }
}